#ifndef SOCKET_HANDER_H
#define SOCKET_HANDER_H

#include <sys/select.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

/**
 * @brief The SocketHander class
 *  专用的socket接口封装
 */
class SocketHander
{
public:
    union sockaddr_ip
    {
        struct sockaddr         sa;
        struct sockaddr_in      v4;
        struct sockaddr_in6     v6;
    };
    SocketHander();
    ~SocketHander();

    //! 创建一个绑定的sock，用于服务端
    bool createBindSock(const char *ip, int port, bool isTcp = true, bool isIpv4 = true);

    //! 创建一个连接的sock，用于客户端
    bool createConnectSock(const char *ip, int port, bool isTcp = true, bool isIpv4 = true);

    //! 从服务端内部队列中，accept一个客户端连接
    bool acceptSock(int sock_fd);

    //! listen socket, 允许绑定地址快速重用
    bool listenSock(int conns = 10);

    //! 设置组播属性
    bool setOptMulticast(const char *multiaddr, const char *interface = nullptr);
    bool removeMulticast(const char *multiaddr, const char *interface);

    //! 设置socket连接属性是否阻塞
    bool setOptBlock(bool bflag);

    //! 绑定设备端口, “wlan0, eth0”
    bool setOptBindIoDevice(const char *iface);

    //! 判断连接是否存在（针对TCP协议）
    bool isEstablished() const;

    //! 写规定长度的数据，内部可能会写多次
    bool writeData(const char *data, int len);

    //! 读规定长度的数据，内部可能会多次度数据，直到读满
    bool readData(char *data, int len);

    //! 只是调用recv，接收一次数据，可能没有达到len长度
    int  readOne(char *data, int len);

    //! 主动关闭，连接
    void closeSock();

    //! 等待，可读，单位：毫秒(ms)
    bool selectSock(int ms);
    bool selectWRSock(int ms);

    //! 获取本地端socket地址
    const sockaddr_ip &getLocalAddr();
    const char *getLocalAddr_c();

    //! 获取远端socket地址
    const sockaddr_ip &getRemoteAddr();
    const char *getRemoteAddr_c();

    // ----
    bool setSock(int fd);

    inline int  sock() const { return m_sockfd; }

    inline int  isDead() const { return m_isdead; }
    inline void setDead() { m_isdead = 1; }

    inline int  isNew() const { return m_isNewCreate; }
    inline void setNotNew() { m_isNewCreate = 0; }
    inline void setIsNew() { m_isNewCreate  = 1; }

    inline sockaddr *sockAddr() { return (struct sockaddr*)&m_sockaddr; }
    inline socklen_t *sockLen() { return &m_len; }

    void moveSock();
    void copy(SocketHander *that);
private:
    int          m_sockfd;
    int          m_isdead;
    int          m_isNewCreate;
    socklen_t    m_len;
    sockaddr_ip  m_sockaddr;
};



#endif // SOCKET_HANDER_H
